package org.apache.ocean.main.merge;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.ocean.ClusterConstants;
import org.apache.ocean.main.IndexDocuments;
import org.apache.ocean.main.IndexSchema;
import org.apache.ocean.main.IndexDocuments.IndexDocument;
import org.apache.ocean.main.client.OceanXML;
import org.apache.ocean.main.client.SearchClient;
import org.apache.ocean.main.client.SearchClient.Batch;
import org.apache.ocean.main.http.HttpParameters;
import org.apache.ocean.main.http.HttpTimeout;
import org.apache.ocean.main.search.Search.Result;
import org.apache.ocean.main.server.TransactionServlet.Response;
import org.apache.ocean.main.util.Constants;
import org.apache.ocean.main.util.PrintStringWriter;
import org.apache.ocean.main.util.Timeout;
import org.apache.ocean.main.util.Util;
import org.apache.ocean.main.util.XMLUtil;
import org.jdom.Element;

public class MergeServlet extends HttpServlet {
	public static Logger log = Logger.getLogger(MergeServlet.class.getName());
	private MergeServer mergeServer;

	private OceanXML defaultOceanResponse() throws Exception {
		OceanXML oceanResponse = new OceanXML();
		oceanResponse.addHeader("serverid", mergeServer.getId());
		oceanResponse.addHeader("serverurl", mergeServer.getUrl());
		return oceanResponse;
	}

	public void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException {
		HttpParameters httpParameters = Util.toHttpParameters(servletRequest);
		PrintStringWriter printStringWriter = new PrintStringWriter();
		Response response = new Response(printStringWriter);
		try {
			if (StringUtils.equalsIgnoreCase("post", servletRequest.getMethod())) {
				OceanXML oceanResponse = defaultOceanResponse();
				OceanXML oceanRequest = OceanXML.parse(servletRequest.getReader());
				if (httpParameters.has("action", "writebatch")) {
					handleWriteBatch(httpParameters, oceanRequest, oceanResponse);
				}
				response.contentType = ClusterConstants.CONTENT_TYPE_XML;
				Element responseElement = oceanResponse.toElement();
				XMLUtil.outputElement(responseElement, printStringWriter);
			} else if (StringUtils.equalsIgnoreCase("get", servletRequest.getMethod())) {
				OceanXML oceanResponse = defaultOceanResponse();
				String action = httpParameters.get("action");
				if (StringUtils.isBlank(action)) {
					handleSearch(httpParameters, oceanResponse);
				} else if (StringUtils.equals("nodesupdated", action)) {
					
				}
			}
			servletResponse.setStatus(200);
		} catch (Throwable throwable) {
			try {
				log.log(Level.SEVERE, "", throwable);
				servletResponse.setStatus(500);
				String responseXML = OceanXML.toOceanXMLString(throwable);
				printStringWriter = new PrintStringWriter();
				printStringWriter.print(responseXML);
			} catch (Throwable exTh) {
				log.log(Level.SEVERE, "", throwable);
				log.log(Level.SEVERE, "inside creating exception response", exTh);
				throw new ServletException(exTh);
			}
		} finally {
			if (printStringWriter != null) {
				servletResponse.setContentType(response.contentType);
				PrintWriter writer = servletResponse.getWriter();
				writer.write(printStringWriter.toString());
			}
		}
	}
  
	private void handleWriteBatch(HttpParameters parameters, OceanXML request, OceanXML response) throws Exception {
    String cell = parameters.get("cell");
    Long schemaVersion = parameters.getLong("schemaversion");
    String categoryName = parameters.get("category");
    long timeoutValue = parameters.getLong("timeout", 10 * 1000);
    Timeout timeout = new Timeout(timeoutValue);
    IndexSchema indexSchema = mergeServer.getIndexSchemaLoader().getIndexSchema(schemaVersion, timeout);
    IndexSchema.Category schemaCategory = indexSchema.getCategory(categoryName);
    if (StringUtils.isBlank(cell)) {
    	cell = mergeServer.getNextWriteableCell();
    }
    Batch batch = new Batch(request.getFirstInBody(), schemaCategory);
    IndexDocuments indexDocuments = batch.getDocuments();
    List<String> deletes = batch.getDeletes();
    URL url = mergeServer.getWriteUrl(cell);
    HttpTimeout httpTimeout = new HttpTimeout(1000, (int)timeout.getTimeLeft());
    SearchClient.writeBatch(url, categoryName, schemaVersion, indexDocuments, deletes, timeout.getTimeLeft(), httpTimeout);
	}
	
	private void handleSearch(HttpParameters parameters, OceanXML response) throws Exception {
		ExecutorService threadPool = mergeServer.getThreadPool();
		long schemaVersion = parameters.getLong("schemaversion");
		String categoryName = parameters.get("category");
		IndexSchema indexSchema = mergeServer.getIndexSchemaLoader().getIndexSchema(schemaVersion, new Timeout(1000));
		IndexSchema.Category schemaCategory = indexSchema.getCategory(categoryName);
		List<URL> urls = mergeServer.getSearchUrls();
		MergeSearch mergeSearch = new MergeSearch(urls, parameters, schemaCategory, threadPool);
		Result<IndexDocument> result = mergeSearch.search();
		for (IndexDocument indexDocument : result.getDocs()) {
			String guid = getGuid(indexDocument);
			indexDocument.set(Constants.GUID, guid);
		}
	}
	
	public static String getGuid(IndexDocument indexDocument) {
		String cell = (String)indexDocument.get(Constants.CELL);
		assert cell != null;
		Long id = (Long)indexDocument.get(Constants.ID);
		return cell+"-"+id;
	}
}
